home *** CD-ROM | disk | FTP | other *** search
/ Clickx 115 / Clickx 115.iso / software / tools / windows / tails-i386-0.16.iso / live / filesystem.squashfs / usr / lib / iceweasel / components / nsPrivateBrowsingService.js < prev    next >
Encoding:
JavaScript  |  2013-01-09  |  25.4 KB  |  718 lines

  1. //@line 38 "/tmp/buildd/iceweasel-10.0.12esr/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js"
  2.  
  3. Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
  4.  
  5. //@line 44 "/tmp/buildd/iceweasel-10.0.12esr/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js"
  6.  
  7. ////////////////////////////////////////////////////////////////////////////////
  8. //// Utilities
  9.  
  10. /**
  11.  * Returns true if the string passed in is part of the root domain of the
  12.  * current string.  For example, if this is "www.mozilla.org", and we pass in
  13.  * "mozilla.org", this will return true.  It would return false the other way
  14.  * around.
  15.  */
  16. String.prototype.hasRootDomain = function hasRootDomain(aDomain)
  17. {
  18.   let index = this.indexOf(aDomain);
  19.   // If aDomain is not found, we know we do not have it as a root domain.
  20.   if (index == -1)
  21.     return false;
  22.  
  23.   // If the strings are the same, we obviously have a match.
  24.   if (this == aDomain)
  25.     return true;
  26.  
  27.   // Otherwise, we have aDomain as our root domain iff the index of aDomain is
  28.   // aDomain.length subtracted from our length and (since we do not have an
  29.   // exact match) the character before the index is a dot or slash.
  30.   let prevChar = this[index - 1];
  31.   return (index == (this.length - aDomain.length)) &&
  32.          (prevChar == "." || prevChar == "/");
  33. }
  34.  
  35. ////////////////////////////////////////////////////////////////////////////////
  36. //// Constants
  37.  
  38. const Cc = Components.classes;
  39. const Ci = Components.interfaces;
  40. const Cu = Components.utils;
  41. const Cr = Components.results;
  42.  
  43. const STATE_IDLE = 0;
  44. const STATE_TRANSITION_STARTED = 1;
  45. const STATE_WAITING_FOR_RESTORE = 2;
  46. const STATE_RESTORE_FINISHED = 3;
  47.  
  48. ////////////////////////////////////////////////////////////////////////////////
  49. //// PrivateBrowsingService
  50.  
  51. function PrivateBrowsingService() {
  52.   this._obs = Cc["@mozilla.org/observer-service;1"].
  53.               getService(Ci.nsIObserverService);
  54.   this._obs.addObserver(this, "profile-after-change", true);
  55.   this._obs.addObserver(this, "quit-application-granted", true);
  56.   this._obs.addObserver(this, "private-browsing", true);
  57.   this._obs.addObserver(this, "command-line-startup", true);
  58.   this._obs.addObserver(this, "sessionstore-browser-state-restored", true);
  59.  
  60.   // List of nsIXULWindows we are going to be closing during the transition
  61.   this._windowsToClose = [];
  62. }
  63.  
  64. PrivateBrowsingService.prototype = {
  65.   // Preferences Service
  66.   get _prefs() {
  67.     let prefs = Cc["@mozilla.org/preferences-service;1"].
  68.                 getService(Ci.nsIPrefBranch);
  69.     this.__defineGetter__("_prefs", function() prefs);
  70.     return this._prefs;
  71.   },
  72.  
  73.   // Whether the private browsing mode is currently active or not.
  74.   _inPrivateBrowsing: false,
  75.  
  76.   // Saved browser state before entering the private mode.
  77.   _savedBrowserState: null,
  78.  
  79.   // Whether we're in the process of shutting down
  80.   _quitting: false,
  81.  
  82.   // How to treat the non-private session
  83.   _saveSession: true,
  84.  
  85.   // The current status of the private browsing service
  86.   _currentStatus: STATE_IDLE,
  87.  
  88.   // Whether the private browsing mode has been started automatically (ie. always-on)
  89.   _autoStarted: false,
  90.  
  91.   // List of view source window URIs for restoring later
  92.   _viewSrcURLs: [],
  93.  
  94.   // Whether private browsing has been turned on from the command line
  95.   _lastChangedByCommandLine: false,
  96.  
  97.   // XPCOM registration
  98.   classID: Components.ID("{c31f4883-839b-45f6-82ad-a6a9bc5ad599}"),
  99.  
  100.   QueryInterface: XPCOMUtils.generateQI([Ci.nsIPrivateBrowsingService, 
  101.                                          Ci.nsIObserver,
  102.                                          Ci.nsISupportsWeakReference,
  103.                                          Ci.nsICommandLineHandler]),
  104.  
  105.   _unload: function PBS__destroy() {
  106.     // Force an exit from the private browsing mode on shutdown
  107.     this._quitting = true;
  108.     if (this._inPrivateBrowsing)
  109.       this.privateBrowsingEnabled = false;
  110.   },
  111.  
  112.   _onBeforePrivateBrowsingModeChange: function PBS__onBeforePrivateBrowsingModeChange() {
  113.     // nothing needs to be done here if we're enabling at startup
  114.     if (!this._autoStarted) {
  115.       let ss = Cc["@mozilla.org/browser/sessionstore;1"].
  116.                getService(Ci.nsISessionStore);
  117.       let blankState = JSON.stringify({
  118.         "windows": [{
  119.           "tabs": [{
  120.             "entries": [{
  121.               "url": "about:blank"
  122.             }]
  123.           }],
  124.           "_closedTabs": []
  125.         }]
  126.       });
  127.  
  128.       if (this._inPrivateBrowsing) {
  129.         // save the whole browser state in order to restore all windows/tabs later
  130.         if (this._saveSession && !this._savedBrowserState) {
  131.           if (this._getBrowserWindow())
  132.             this._savedBrowserState = ss.getBrowserState();
  133.           else // no open browser windows, just restore a blank state on exit
  134.             this._savedBrowserState = blankState;
  135.         }
  136.       }
  137.  
  138.       this._closePageInfoWindows();
  139.  
  140.       // save view-source windows URIs and close them
  141.       let viewSrcWindowsEnum = Cc["@mozilla.org/appshell/window-mediator;1"].
  142.                                getService(Ci.nsIWindowMediator).
  143.                                getEnumerator("navigator:view-source");
  144.       while (viewSrcWindowsEnum.hasMoreElements()) {
  145.         let win = viewSrcWindowsEnum.getNext();
  146.         if (this._inPrivateBrowsing) {
  147.           let plainURL = win.gBrowser.currentURI.spec;
  148.           if (plainURL.indexOf("view-source:") == 0) {
  149.             plainURL = plainURL.substr(12);
  150.             this._viewSrcURLs.push(plainURL);
  151.           }
  152.         }
  153.         win.close();
  154.       }
  155.  
  156.       if (!this._quitting && this._saveSession) {
  157.         let browserWindow = this._getBrowserWindow();
  158.  
  159.         // if there are open browser windows, load a dummy session to get a distinct 
  160.         // separation between private and non-private sessions
  161.         if (browserWindow) {
  162.           // set an empty session to transition from/to pb mode, see bug 476463
  163.           ss.setBrowserState(blankState);
  164.  
  165.           // just in case the only remaining window after setBrowserState is different.
  166.           // it probably shouldn't be with the current sessionstore impl, but we shouldn't
  167.           // rely on behaviour the API doesn't guarantee
  168.           browserWindow = this._getBrowserWindow();
  169.           let browser = browserWindow.gBrowser;
  170.  
  171.           // this ensures a clean slate from which to transition into or out of
  172.           // private browsing
  173.           browser.addTab();
  174.           browser.getBrowserForTab(browser.tabContainer.firstChild).stop();
  175.           browser.removeTab(browser.tabContainer.firstChild);
  176.           browserWindow.getInterface(Ci.nsIWebNavigation)
  177.                        .QueryInterface(Ci.nsIDocShellTreeItem)
  178.                        .treeOwner
  179.                        .QueryInterface(Ci.nsIInterfaceRequestor)
  180.                        .getInterface(Ci.nsIXULWindow)
  181.                        .docShell.contentViewer.resetCloseWindow();
  182.         }
  183.       }
  184.     }
  185.     else
  186.       this._saveSession = false;
  187.   },
  188.  
  189.   _onAfterPrivateBrowsingModeChange: function PBS__onAfterPrivateBrowsingModeChange() {
  190.     // nothing to do here if we're enabling at startup or the current session is being
  191.     // used
  192.     if (!this._autoStarted && this._saveSession) {
  193.       let ss = Cc["@mozilla.org/browser/sessionstore;1"].
  194.                getService(Ci.nsISessionStore);
  195.       // if we have transitioned out of private browsing mode and the session is
  196.       // to be restored, do it now
  197.       if (!this._inPrivateBrowsing) {
  198.         this._currentStatus = STATE_WAITING_FOR_RESTORE;
  199.         if (!this._getBrowserWindow()) {
  200.           ss.init(null);
  201.         }
  202.         ss.setBrowserState(this._savedBrowserState);
  203.         this._savedBrowserState = null;
  204.  
  205.         this._closePageInfoWindows();
  206.  
  207.         // re-open all view-source windows
  208.         let windowWatcher = Cc["@mozilla.org/embedcomp/window-watcher;1"].
  209.                             getService(Ci.nsIWindowWatcher);
  210.         this._viewSrcURLs.forEach(function(uri) {
  211.           let args = Cc["@mozilla.org/supports-array;1"].
  212.                      createInstance(Ci.nsISupportsArray);
  213.           let str = Cc["@mozilla.org/supports-string;1"].
  214.                     createInstance(Ci.nsISupportsString);
  215.           str.data = uri;
  216.           args.AppendElement(str);
  217.           args.AppendElement(null); // charset
  218.           args.AppendElement(null); // page descriptor
  219.           args.AppendElement(null); // line number
  220.           let forcedCharset = Cc["@mozilla.org/supports-PRBool;1"].
  221.                               createInstance(Ci.nsISupportsPRBool);
  222.           forcedCharset.data = false;
  223.           args.AppendElement(forcedCharset);
  224.           windowWatcher.openWindow(null, "chrome://global/content/viewSource.xul",
  225.             "_blank", "all,dialog=no", args);
  226.         });
  227.         this._viewSrcURLs = [];
  228.       }
  229.       else {
  230.         // otherwise, if we have transitioned into private browsing mode, load
  231.         // about:privatebrowsing
  232.         let privateBrowsingState = {
  233.           "windows": [{
  234.             "tabs": [{
  235.               "entries": [{
  236.                 "url": "about:privatebrowsing"
  237.               }]
  238.             }],
  239.             "_closedTabs": []
  240.           }]
  241.         };
  242.         // Transition into private browsing mode
  243.         this._currentStatus = STATE_WAITING_FOR_RESTORE;
  244.         if (!this._getBrowserWindow()) {
  245.           ss.init(null);
  246.         }
  247.         ss.setBrowserState(JSON.stringify(privateBrowsingState));
  248.       }
  249.     }
  250.   },
  251.  
  252.   _notifyIfTransitionComplete: function PBS__notifyIfTransitionComplete() {
  253.     switch (this._currentStatus) {
  254.       case STATE_TRANSITION_STARTED:
  255.         // no session store operation was needed, so just notify of transition completion
  256.       case STATE_RESTORE_FINISHED:
  257.         // restore has been completed
  258.         this._currentStatus = STATE_IDLE;
  259.         this._obs.notifyObservers(null, "private-browsing-transition-complete", "");
  260.         break;
  261.       case STATE_WAITING_FOR_RESTORE:
  262.         // too soon to notify...
  263.         break;
  264.       case STATE_IDLE:
  265.         // no need to notify
  266.         break;
  267.       default:
  268.         // unexpected state observed
  269.         Cu.reportError("Unexpected private browsing status reached: " +
  270.                        this._currentStatus);
  271.         break;
  272.     }
  273.   },
  274.  
  275.   _canEnterPrivateBrowsingMode: function PBS__canEnterPrivateBrowsingMode() {
  276.     let cancelEnter = Cc["@mozilla.org/supports-PRBool;1"].
  277.                       createInstance(Ci.nsISupportsPRBool);
  278.     cancelEnter.data = false;
  279.     this._obs.notifyObservers(cancelEnter, "private-browsing-cancel-vote", "enter");
  280.     return !cancelEnter.data;
  281.   },
  282.  
  283.   _canLeavePrivateBrowsingMode: function PBS__canLeavePrivateBrowsingMode() {
  284.     let cancelLeave = Cc["@mozilla.org/supports-PRBool;1"].
  285.                       createInstance(Ci.nsISupportsPRBool);
  286.     cancelLeave.data = false;
  287.     this._obs.notifyObservers(cancelLeave, "private-browsing-cancel-vote", "exit");
  288.     return !cancelLeave.data;
  289.   },
  290.  
  291.   _getBrowserWindow: function PBS__getBrowserWindow() {
  292.     var wm = Cc["@mozilla.org/appshell/window-mediator;1"].
  293.              getService(Ci.nsIWindowMediator);
  294.  
  295.     var win = wm.getMostRecentWindow("navigator:browser");
  296.  
  297.     // We don't just return |win| now because of bug 528706.
  298.  
  299.     if (!win)
  300.       return null;
  301.     if (!win.closed)
  302.       return win;
  303.  
  304. //@line 343 "/tmp/buildd/iceweasel-10.0.12esr/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js"
  305.     win = null;
  306.     var windowsEnum = wm.getEnumerator("navigator:browser");
  307.     // this is oldest to newest, so this gets a bit ugly
  308.     while (windowsEnum.hasMoreElements()) {
  309.       let nextWin = windowsEnum.getNext();
  310.       if (!nextWin.closed)
  311.         win = nextWin;
  312.     }
  313.     return win;
  314. //@line 361 "/tmp/buildd/iceweasel-10.0.12esr/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js"
  315.   },
  316.  
  317.   _ensureCanCloseWindows: function PBS__ensureCanCloseWindows() {
  318.     // whether we should save and close the current session
  319.     this._saveSession = true;
  320.     try {
  321.       if (this._prefs.getBoolPref("browser.privatebrowsing.keep_current_session")) {
  322.         this._saveSession = false;
  323.         return;
  324.       }
  325.     } catch (ex) {}
  326.  
  327.     let windowMediator = Cc["@mozilla.org/appshell/window-mediator;1"].
  328.                          getService(Ci.nsIWindowMediator);
  329.     let windowsEnum = windowMediator.getEnumerator("navigator:browser");
  330.  
  331.     while (windowsEnum.hasMoreElements()) {
  332.       let win = windowsEnum.getNext();
  333.       if (win.closed)
  334.         continue;
  335.       let xulWin = win.QueryInterface(Ci.nsIInterfaceRequestor).
  336.                    getInterface(Ci.nsIWebNavigation).
  337.                    QueryInterface(Ci.nsIDocShellTreeItem).
  338.                    treeOwner.QueryInterface(Ci.nsIInterfaceRequestor).
  339.                    getInterface(Ci.nsIXULWindow);
  340.       if (xulWin.docShell.contentViewer.permitUnload(true))
  341.         this._windowsToClose.push(xulWin);
  342.       else
  343.         throw Cr.NS_ERROR_ABORT;
  344.     }
  345.   },
  346.  
  347.   _closePageInfoWindows: function PBS__closePageInfoWindows() {
  348.     let pageInfoEnum = Cc["@mozilla.org/appshell/window-mediator;1"].
  349.                        getService(Ci.nsIWindowMediator).
  350.                        getEnumerator("Browser:page-info");
  351.     while (pageInfoEnum.hasMoreElements()) {
  352.       let win = pageInfoEnum.getNext();
  353.       win.close();
  354.     }
  355.   },
  356.  
  357.   // nsIObserver
  358.  
  359.   observe: function PBS_observe(aSubject, aTopic, aData) {
  360.     switch (aTopic) {
  361.       case "profile-after-change":
  362.         // If the autostart prefs has been set, simulate entering the
  363.         // private browsing mode upon startup.
  364.         // This won't interfere with the session store component, because
  365.         // that component will be initialized on final-ui-startup.
  366.         if (!this._autoStarted) {
  367.           this._autoStarted = this._prefs.getBoolPref("browser.privatebrowsing.autostart");
  368.           if (this._autoStarted)
  369.             this.privateBrowsingEnabled = true;
  370.         }
  371.         this._obs.removeObserver(this, "profile-after-change");
  372.         break;
  373.       case "quit-application-granted":
  374.         this._unload();
  375.         break;
  376.       case "private-browsing":
  377.         // clear all auth tokens
  378.         let sdr = Cc["@mozilla.org/security/sdr;1"].
  379.                   getService(Ci.nsISecretDecoderRing);
  380.         sdr.logoutAndTeardown();
  381.     
  382.         // clear plain HTTP auth sessions
  383.         let authMgr = Cc['@mozilla.org/network/http-auth-manager;1'].
  384.                       getService(Ci.nsIHttpAuthManager);
  385.         authMgr.clearAll();
  386.  
  387.         try {
  388.           this._prefs.deleteBranch("geo.wifi.access_token.");
  389.         } catch (ex) {}
  390.  
  391.         if (!this._inPrivateBrowsing) {
  392.           // Clear the error console
  393.           let consoleService = Cc["@mozilla.org/consoleservice;1"].
  394.                                getService(Ci.nsIConsoleService);
  395.           consoleService.logStringMessage(null); // trigger the listeners
  396.           consoleService.reset();
  397.         }
  398.         break;
  399.       case "command-line-startup":
  400.         this._obs.removeObserver(this, "command-line-startup");
  401.         aSubject.QueryInterface(Ci.nsICommandLine);
  402.         if (aSubject.findFlag("private", false) >= 0) {
  403.           this.privateBrowsingEnabled = true;
  404.           this._autoStarted = true;
  405.           this._lastChangedByCommandLine = true;
  406.         }
  407.         else if (aSubject.findFlag("private-toggle", false) >= 0) {
  408.           this._lastChangedByCommandLine = true;
  409.         }
  410.         break;
  411.       case "sessionstore-browser-state-restored":
  412.         if (this._currentStatus == STATE_WAITING_FOR_RESTORE) {
  413.           this._currentStatus = STATE_RESTORE_FINISHED;
  414.           this._notifyIfTransitionComplete();
  415.         }
  416.         break;
  417.     }
  418.   },
  419.  
  420.   // nsICommandLineHandler
  421.  
  422.   handle: function PBS_handle(aCmdLine) {
  423.     if (aCmdLine.handleFlag("private", false))
  424.       aCmdLine.preventDefault = true; // It has already been handled
  425.     else if (aCmdLine.handleFlag("private-toggle", false)) {
  426.       if (this._autoStarted) {
  427.         throw Cr.NS_ERROR_ABORT;
  428.       }
  429.       this.privateBrowsingEnabled = !this.privateBrowsingEnabled;
  430.       this._lastChangedByCommandLine = true;
  431.     }
  432.   },
  433.  
  434.   get helpInfo() {
  435.     return "  -private           Enable private browsing mode.\n" +
  436.            "  -private-toggle    Toggle private browsing mode.\n";
  437.   },
  438.  
  439.   // nsIPrivateBrowsingService
  440.  
  441.   /**
  442.    * Return the current status of private browsing.
  443.    */
  444.   get privateBrowsingEnabled() {
  445.     return this._inPrivateBrowsing;
  446.   },
  447.  
  448.   /**
  449.    * Enter or leave private browsing mode.
  450.    */
  451.   set privateBrowsingEnabled(val) {
  452.     // Allowing observers to set the private browsing status from their
  453.     // notification handlers is not desired, because it will change the
  454.     // status of the service while it's in the process of another transition.
  455.     // So, we detect a reentrant call here and throw an error.
  456.     // This is documented in nsIPrivateBrowsingService.idl.
  457.     if (this._currentStatus != STATE_IDLE)
  458.       throw Cr.NS_ERROR_FAILURE;
  459.  
  460.     if (val == this._inPrivateBrowsing)
  461.       return;
  462.  
  463.     try {
  464.       if (val) {
  465.         if (!this._canEnterPrivateBrowsingMode())
  466.           return;
  467.       }
  468.       else {
  469.         if (!this._canLeavePrivateBrowsingMode())
  470.           return;
  471.       }
  472.  
  473.       this._ensureCanCloseWindows();
  474.  
  475.       // start the transition now that we know that we can
  476.       this._currentStatus = STATE_TRANSITION_STARTED;
  477.  
  478.       this._autoStarted = this._prefs.getBoolPref("browser.privatebrowsing.autostart");
  479.       this._inPrivateBrowsing = val != false;
  480.  
  481.       let data = val ? "enter" : "exit";
  482.  
  483.       let quitting = Cc["@mozilla.org/supports-PRBool;1"].
  484.                      createInstance(Ci.nsISupportsPRBool);
  485.       quitting.data = this._quitting;
  486.  
  487.       // notify observers of the pending private browsing mode change
  488.       this._obs.notifyObservers(quitting, "private-browsing-change-granted", data);
  489.  
  490.       // destroy the current session and start initial cleanup
  491.       this._onBeforePrivateBrowsingModeChange();
  492.  
  493.       this._obs.notifyObservers(quitting, "private-browsing", data);
  494.  
  495.       // load the appropriate session
  496.       this._onAfterPrivateBrowsingModeChange();
  497.     } catch (ex) {
  498.       // We aborted the transition to/from private browsing, we must restore the
  499.       // beforeunload handling on all the windows for which we switched it off.
  500.       for (let i = 0; i < this._windowsToClose.length; i++)
  501.         this._windowsToClose[i].docShell.contentViewer.resetCloseWindow();
  502.       // We don't log an error when the transition is canceled from beforeunload
  503.       if (ex != Cr.NS_ERROR_ABORT)
  504.         Cu.reportError("Exception thrown while processing the " +
  505.           "private browsing mode change request: " + ex.toString());
  506.     } finally {
  507.       this._windowsToClose = [];
  508.       this._notifyIfTransitionComplete();
  509.       this._lastChangedByCommandLine = false;
  510.     }
  511.   },
  512.  
  513.   /**
  514.    * Whether private browsing has been started automatically.
  515.    */
  516.   get autoStarted() {
  517.     return this._inPrivateBrowsing && this._autoStarted;
  518.   },
  519.  
  520.   /**
  521.    * Whether the latest transition was initiated from the command line.
  522.    */
  523.   get lastChangedByCommandLine() {
  524.     return this._lastChangedByCommandLine;
  525.   },
  526.  
  527.   removeDataFromDomain: function PBS_removeDataFromDomain(aDomain)
  528.   {
  529.  
  530.     // clear any and all network geolocation provider sessions
  531.     try {
  532.         this._prefs.deleteBranch("geo.wifi.access_token.");
  533.     } catch (e) {}
  534.     
  535.     // History
  536.     let (bh = Cc["@mozilla.org/browser/global-history;2"].
  537.               getService(Ci.nsIBrowserHistory)) {
  538.       bh.removePagesFromHost(aDomain, true);
  539.     }
  540.  
  541.     // Cache
  542.     let (cs = Cc["@mozilla.org/network/cache-service;1"].
  543.               getService(Ci.nsICacheService)) {
  544.       // NOTE: there is no way to clear just that domain, so we clear out
  545.       //       everything)
  546.       try {
  547.         cs.evictEntries(Ci.nsICache.STORE_ANYWHERE);
  548.       } catch (ex) {
  549.         Cu.reportError("Exception thrown while clearing the cache: " +
  550.           ex.toString());
  551.       }
  552.     }
  553.  
  554.     // Image Cache
  555.     let (imageCache = Cc["@mozilla.org/image/cache;1"].
  556.                       getService(Ci.imgICache)) {
  557.       try {
  558.         imageCache.clearCache(false); // true=chrome, false=content
  559.       } catch (ex) {
  560.         Cu.reportError("Exception thrown while clearing the image cache: " +
  561.           ex.toString());
  562.       }
  563.     }
  564.  
  565.     // Cookies
  566.     let (cm = Cc["@mozilla.org/cookiemanager;1"].
  567.               getService(Ci.nsICookieManager2)) {
  568.       let enumerator = cm.getCookiesFromHost(aDomain);
  569.       while (enumerator.hasMoreElements()) {
  570.         let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie);
  571.         cm.remove(cookie.host, cookie.name, cookie.path, false);
  572.       }
  573.     }
  574.  
  575.     // Plugin data
  576.     const phInterface = Ci.nsIPluginHost;
  577.     const FLAG_CLEAR_ALL = phInterface.FLAG_CLEAR_ALL;
  578.     let (ph = Cc["@mozilla.org/plugin/host;1"].getService(phInterface)) {
  579.       let tags = ph.getPluginTags();
  580.       for (let i = 0; i < tags.length; i++) {
  581.         try {
  582.           ph.clearSiteData(tags[i], aDomain, FLAG_CLEAR_ALL, -1);
  583.         } catch (e) {
  584.           // Ignore errors from the plugin
  585.         }
  586.       }
  587.     }
  588.  
  589.     // Downloads
  590.     let (dm = Cc["@mozilla.org/download-manager;1"].
  591.               getService(Ci.nsIDownloadManager)) {
  592.       // Active downloads
  593.       let enumerator = dm.activeDownloads;
  594.       while (enumerator.hasMoreElements()) {
  595.         let dl = enumerator.getNext().QueryInterface(Ci.nsIDownload);
  596.         if (dl.source.host.hasRootDomain(aDomain)) {
  597.           dm.cancelDownload(dl.id);
  598.           dm.removeDownload(dl.id);
  599.         }
  600.       }
  601.  
  602.       // Completed downloads
  603.       let db = dm.DBConnection;
  604.       // NOTE: This is lossy, but we feel that it is OK to be lossy here and not
  605.       //       invoke the cost of creating a URI for each download entry and
  606.       //       ensure that the hostname matches.
  607.       let stmt = db.createStatement(
  608.         "DELETE FROM moz_downloads " +
  609.         "WHERE source LIKE ?1 ESCAPE '/' " +
  610.         "AND state NOT IN (?2, ?3, ?4)"
  611.       );
  612.       let pattern = stmt.escapeStringForLIKE(aDomain, "/");
  613.       stmt.bindByIndex(0, "%" + pattern + "%");
  614.       stmt.bindByIndex(1, Ci.nsIDownloadManager.DOWNLOAD_DOWNLOADING);
  615.       stmt.bindByIndex(2, Ci.nsIDownloadManager.DOWNLOAD_PAUSED);
  616.       stmt.bindByIndex(3, Ci.nsIDownloadManager.DOWNLOAD_QUEUED);
  617.       try {
  618.         stmt.execute();
  619.       }
  620.       finally {
  621.         stmt.finalize();
  622.       }
  623.  
  624.       // We want to rebuild the list if the UI is showing, so dispatch the
  625.       // observer topic
  626.       let os = Cc["@mozilla.org/observer-service;1"].
  627.                getService(Ci.nsIObserverService);
  628.       os.notifyObservers(null, "download-manager-remove-download", null);
  629.     }
  630.  
  631.     // Passwords
  632.     let (lm = Cc["@mozilla.org/login-manager;1"].
  633.               getService(Ci.nsILoginManager)) {
  634.       // Clear all passwords for domain
  635.       try {
  636.         let logins = lm.getAllLogins();
  637.         for (let i = 0; i < logins.length; i++)
  638.           if (logins[i].hostname.hasRootDomain(aDomain))
  639.             lm.removeLogin(logins[i]);
  640.       }
  641.       // XXXehsan: is there a better way to do this rather than this
  642.       // hacky comparison?
  643.       catch (ex if ex.message.indexOf("User canceled Master Password entry") != -1) { }
  644.  
  645.       // Clear any "do not save for this site" for this domain
  646.       let disabledHosts = lm.getAllDisabledHosts();
  647.       for (let i = 0; i < disabledHosts.length; i++)
  648.         if (disabledHosts[i].hasRootDomain(aDomain))
  649.           lm.setLoginSavingEnabled(disabledHosts, true);
  650.     }
  651.  
  652.     // Permissions
  653.     let (pm = Cc["@mozilla.org/permissionmanager;1"].
  654.               getService(Ci.nsIPermissionManager)) {
  655.       // Enumerate all of the permissions, and if one matches, remove it
  656.       let enumerator = pm.enumerator;
  657.       while (enumerator.hasMoreElements()) {
  658.         let perm = enumerator.getNext().QueryInterface(Ci.nsIPermission);
  659.         if (perm.host.hasRootDomain(aDomain))
  660.           pm.remove(perm.host, perm.type);
  661.       }
  662.     }
  663.  
  664.     // Content Preferences
  665.     let (cp = Cc["@mozilla.org/content-pref/service;1"].
  666.               getService(Ci.nsIContentPrefService)) {
  667.       let db = cp.DBConnection;
  668.       // First we need to get the list of "groups" which are really just domains
  669.       let names = [];
  670.       let stmt = db.createStatement(
  671.         "SELECT name " +
  672.         "FROM groups " +
  673.         "WHERE name LIKE ?1 ESCAPE '/'"
  674.       );
  675.       let pattern = stmt.escapeStringForLIKE(aDomain, "/");
  676.       stmt.bindByIndex(0, "%" + pattern);
  677.       try {
  678.         while (stmt.executeStep())
  679.           if (stmt.getString(0).hasRootDomain(aDomain))
  680.             names.push(stmt.getString(0));
  681.       }
  682.       finally {
  683.         stmt.finalize();
  684.       }
  685.  
  686.       // Now, for each name we got back, remove all of its prefs.
  687.       for (let i = 0; i < names.length; i++) {
  688.         let uri = names[i];
  689.         let enumerator = cp.getPrefs(uri).enumerator;
  690.         while (enumerator.hasMoreElements()) {
  691.           let pref = enumerator.getNext().QueryInterface(Ci.nsIProperty);
  692.           cp.removePref(uri, pref.name);
  693.         }
  694.       }
  695.     }
  696.  
  697.     // Indexed DB
  698.     let (idbm = Cc["@mozilla.org/dom/indexeddb/manager;1"].
  699.                 getService(Ci.nsIIndexedDatabaseManager)) {
  700.       // delete data from both HTTP and HTTPS sites
  701.       let caUtils = {};
  702.       let scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
  703.                          getService(Ci.mozIJSSubScriptLoader);
  704.       scriptLoader.loadSubScript("chrome://global/content/contentAreaUtils.js",
  705.                                  caUtils);
  706.       let httpURI = caUtils.makeURI("http://" + aDomain);
  707.       let httpsURI = caUtils.makeURI("https://" + aDomain);
  708.       idbm.clearDatabasesForURI(httpURI);
  709.       idbm.clearDatabasesForURI(httpsURI);
  710.     }
  711.  
  712.     // Everybody else (including extensions)
  713.     this._obs.notifyObservers(null, "browser:purge-domain-data", aDomain);
  714.   }
  715. };
  716.  
  717. var NSGetFactory = XPCOMUtils.generateNSGetFactory([PrivateBrowsingService]);
  718.